﻿using Easy.Common.Enums;
using Easy.Common.Extension;
using Easy.Common.Helper;
using Easy.Common.Helper.JWT;
using Easy.Common.Params;
using Easy.Common.Results;
using Easy.Services.DbContexts;
using Easy.Services.Dtos;
using Easy.Services.Entities;
using Easy.Services.Interface;
using System.Linq.Expressions;

namespace Easy.Services.Core
{
    internal class UserService : IUserService
    {

        public long Add(User user)
        {
            using MySQLDbContext db = new();
            BaseService<User> baseService = new(db);
            return baseService.AddBase(user);

        }

        public APIResult Register(LoginDTO dto, string ip)
        {
            APIResult result = new();

            if (dto.UserName.Length < 2 || dto.UserName.Length > 50)
            {
                result.Message = "长度在 2 到 50 个字符";
                return result;
            }
            if (!dto.UserName.IsValidUserName() && !dto.UserName.IsEmail())
            {
                result.Message = "用户名包含特殊的字符";
                return result;
            }
            if (Exist(u => u.UserName.Equals(dto.UserName) && u.IsDelete == false))
            {
                result.Message = "用户名已存在";
                return result;
            }
            var user = new User
            {
                StaffPhoto = "",
                CreaterName = dto.UserName,
                CreaterId = 1,
                EditName = dto.UserName,
                UserName = dto.UserName,
                PasswordSalt = CommonHelper.CreateVerifyCode(6)
            };
            user.Password = CommonHelper.CalcMD5(dto.Password + user.PasswordSalt);
            user.CreateIP = ip;
            var res = Add(user);
            if (res > 0)
            {
                result.Success = true;
                result.Message = "添加成功";
                var tokenModel = new TokenModelJwt
                {
                    Id = res,
                    UserName = user.UserName,
                };
                var token = JwtHelper.EncodeJwt(tokenModel);
                result.Data = new TokenDTO(token);
            }
            else
            {
                result.Message = "添加失败";
            }
            return result;

        }

        public APIResult Login(LoginDTO login)
        {
            APIResult result = new();
            if (login.UserName.Length < 2 || login.UserName.Length > 50)
            {
                result.Message = "长度在 2 到 50 个字符";
                return result;
            }
            if (!login.UserName.IsValidUserName() && !login.UserName.IsEmail())
            {
                result.Message = "用户名包含特殊的字符";
                return result;
            }
            var user = Get(ui => ui.UserName == login.UserName || ui.Email == login.UserName);
            if (user == null)
            {
                result.Message = "用户名或密码错误";
                return result;
            }
            if (user.IsFreeze == UserFreezeEnum.Freeze.GetHashCode())
            {
                result.Message = "该用户名已被冻结,请联系管理员";
                return result;
            }
            //登录次数99并且是今天最后一次登录
            if (user.LoginTotalCount >= 99 && DateTime.UtcNow.Date == user.LastLoginDate.Date)
            {
                result.Message = "登录总次数已到上限";
                return result;
            }
            //错误登录次数>=5，最后一次登录错误时间在30分钟之内
            if ((user.LoginErrorCount >= 5 && user.LastLoginDate > DateTime.UtcNow.AddMinutes(-30)))
            {
                //TimeSpan代表时间段，日期相减就代表相差的时间段
                TimeSpan? leftTimeSpan = TimeSpan.FromMinutes(30) - (DateTime.UtcNow - user.LastLoginDate);
                result.Message = string.Format("账号已被锁定，请{0}分钟后再试", (int)leftTimeSpan.Value.TotalMinutes);
                return result;
            }
            if (user.Password == CommonHelper.CalcMD5(login.Password + user.PasswordSalt))
            {
                result.Success = true;
                ResetLoginError(user);
                var tokenModel = new TokenModelJwt
                {
                    Id = user.Id,
                    UserName = user.UserName,
                    Avatar = user.StaffPhoto
                };
                var token = JwtHelper.EncodeJwt(tokenModel);
                result.Data = new TokenDTO(token);

            }
            else
            {
                RecordLoginError(login.UserName);
                result.Data = "";
                result.Message = "用户名或密码错误";
            }
            return result;

        }

        public APIResult RecordLoginError(string userName)
        {
            APIResult result = new();
            var userInfo = Get(u => u.UserName.Equals(userName));
            if (userInfo == null)
            {
                result.Message = $"用户名:{userName}不存在";
                return result;
            }
            if (DateTime.UtcNow.Date == userInfo.LastLoginDate.AddDays(1).Date)
            {
                userInfo.LoginErrorCount = 1;
                userInfo.LoginTotalCount = 1;
            }
            else
            {
                userInfo.LoginErrorCount++;
                userInfo.LoginTotalCount++;
            }
            userInfo.LastLoginDate = DateTime.UtcNow;
            Update(userInfo);
            result.Success = true;
            return result;

        }

        public APIResult ResetLoginError(User user)
        {
            APIResult result = new();
            user.LoginTotalCount++;
            if (DateTime.UtcNow.Date == user.LastLoginDate.AddDays(1).Date)
            {
                user.LoginTotalCount = 1;
            }
            user.LoginErrorCount = 0;
            user.LastLoginDate = DateTime.UtcNow;
            Update(user);
            result.Success = true;
            return result;

        }

        public User Get(Expression<Func<User, bool>> expression)
        {
            using MySQLDbContext db = new();
            BaseService<User> baseService = new(db);
            return baseService.GetBase(expression);

        }

        public bool Update(User user)
        {
            using MySQLDbContext db = new();
            BaseService<User> baseService = new(db);
            return baseService.UpdateBase(user);

        }

        public APIResult GetProfile(TokenModelJwt tokenModel)
        {
            APIResult result = new();
            if (tokenModel == null)
            {
                result.Message = "登录信息失效";
                return result;
            }
            var user = Get(u => u.Id.Equals(tokenModel.Id));
            ProfileDTO profile = new()
            {
                City = user.City,
                Company = user.Company,
                CompanyId = user.CompanyId,
                DepartmentName = user.DepartmentName,
                Mobile = user.Mobile,
                Roles = GetRoles(tokenModel.Id),
                StaffPhoto = user.StaffPhoto,
                UserId = user.Id,
                UserName = user.UserName
            };
            result.Data = profile;
            result.Success = true;
            return result;
        }

        public Roles GetRoles(long id)
        {
            Roles roles = new();
            using MySQLDbContext db = new();
            var queryMenus = from p in db.Permissions
                             join rpr in db.RolePermissionRelations
                             on p.Id equals rpr.PermissionId
                             join urr in db.UserRoleRelations
                             on rpr.RoleId equals urr.RoleId
                             where urr.UserId == id  && p.Type == 1 && p.EnVisible == 1 && urr.IsDelete == false
                             select p.Code;
            roles.Menus = [.. queryMenus];

            var queryPoints = from p in db.Permissions
                              join rpr in db.RolePermissionRelations
                              on p.Id equals rpr.PermissionId
                              join urr in db.UserRoleRelations
                              on rpr.RoleId equals urr.RoleId
                              where urr.UserId == id && p.Type == 2 && p.EnVisible == 1 && urr.IsDelete == false
                              select p.Code;
            roles.Points = [.. queryPoints];
            return roles;
        }

        public bool Exist(Expression<Func<User, bool>> expression)
        {
            using MySQLDbContext db = new();
            BaseService<User> baseService = new(db);
            return baseService.Exist(expression);

        }

        public APIResult UpdatePassword(UpdatePasswordDTO dto, TokenModelJwt tokenModel)
        {
            APIResult result = new();
            using MySQLDbContext db = new();
            BaseService<User> baseService = new(db);
            var user = Get(u => u.Id == tokenModel.Id);
            if (user == null)
            {
                result.Message = "登录信息失效";
                return result;
            }
            user.Password = CommonHelper.CalcMD5(dto.NewPassword + user.PasswordSalt);
            result.Success = Update(user);
            result.Message = result.Success ? "修改成功" : "修改失败";
            return result;

        }

        public APIResult GetManagerList()
        {
            APIResult result = new();
            using MySQLDbContext db = new();
            var dtos = from u in db.Users
                       join urr in db.UserRoleRelations
                       on u.Id equals urr.RoleId
                       join rpr in db.RolePermissionRelations
                       on urr.RoleId equals rpr.RoleId
                       where rpr.PermissionId == 3
                       select new { u.Id, u.UserName };
            result.Data = dtos.ToList();
            result.Success = dtos.Any();
            return result;
        }

        public APIResult GetPage(UserPageParam param)
        {
            APIResult result = new();
            if (param.Page <= 0 || param.PageSize <= 0)
            {
                result.Message = "分页参数无效";
                return result;
            }
            PageResult<List<UserDTO>> pageResult = new();
            using MySQLDbContext db = new();
            BaseService<User> baseService = new(db);
            List<UserDTO> list = [];
            if (param.Keyword.IsNullOrWhiteSpace())
            {
                list = baseService.GetPage(page: new() { Page = param.Page, PageSize = param.PageSize }, u => u.DepartmentId == param.DepartmentId).Select(user => new UserDTO()
                {
                    Id = user.Id,
                    DepartmentId = user.DepartmentId.Value,
                    DepartmentName = user.DepartmentName,
                    FormOfEmployment = user?.FormOfEmployment ?? 2,
                    Mobile = user.Mobile,
                    StaffPhoto = user.StaffPhoto,
                    TimeOfEntry = user.TimeOfEntry,
                    UserName = user.UserName,
                    WorkNumber = user.WorkNumber

                }).ToList();
            }
            else
            {
                list = baseService.GetPage(page: new() { Page = param.Page, PageSize = param.PageSize }, u => u.DepartmentId == param.DepartmentId && u.UserName.Contains(param.Keyword)).Select(user => new UserDTO()
                {
                    Id = user.Id,
                    DepartmentId = user.DepartmentId.Value,
                    DepartmentName = user.DepartmentName,
                    FormOfEmployment = user?.FormOfEmployment ?? 2,
                    Mobile = user.Mobile,
                    StaffPhoto = user.StaffPhoto,
                    TimeOfEntry = user.TimeOfEntry,
                    UserName = user.UserName,
                    WorkNumber = user.WorkNumber

                }).ToList();
            }

            pageResult.Rows = list;
            if (param.Keyword.IsNullOrWhiteSpace())
            {
                pageResult.Total = baseService.GetTotalCount(u => u.DepartmentId == param.DepartmentId);
            }
            else
            {
                pageResult.Total = baseService.GetTotalCount(u => u.DepartmentId == param.DepartmentId && u.UserName.Contains(param.Keyword));
            }
            result.Success = list?.Count > 0;
            result.Message = result.Success ? "获取成功" : "获取失败";
            result.Data = pageResult;
            return result;

        }

        public APIResult AddUser(User user)
        {
            APIResult result = new();
            if (Exist(u => u.UserName.Equals(user.UserName) && u.IsDelete == false))
            {
                result.Message = "用户名已存在";
                return result;
            }
            using MySQLDbContext db = new();
            BaseService<User> baseService = new(db);
            var res = baseService.AddBase(user);
            result.Success = res > 0;
            return result;

        }

        public bool Delete(User user)
        {
            using MySQLDbContext db = new();
            BaseService<User> baseService = new(db);
            user.SetDelete();
            return baseService.UpdateBase(user);

        }

        public long[] GetRoleIds(long id)
        {
            using MySQLDbContext db = new();
            BaseService<UserRoleRelation> baseService = new(db);
            var ids = baseService.GetList(ur=>ur.UserId==id).Select(ur=>ur.RoleId).ToArray();
            return ids;

        }


        public long GetTotal(Expression<Func<User, bool>> whereExpression = null, bool includeDelete = false)
        {
            using MySQLDbContext db = new();
            BaseService<User> baseService = new(db);
            return baseService.GetTotalCount(whereExpression, includeDelete);

        }


    }
}
